﻿using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Input;
using LukasKopenec.LocalizationSupport;
using Notoric.Gui.Windows;

namespace Notoric.Gui.Commands
{
    /// <summary>
    /// A Common Base Class for Commands that will be used in Ribbon.
    /// </summary>
    public abstract class RibbonCommand : ICommand, INotifyPropertyChanged
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="RibbonCommand"/> instance.
        /// </summary>
        /// <param name="window">
        /// <para>
        /// Type: <see cref="MainWindow"/>
        /// </para>
        /// <para>
        /// The main application window.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// The <paramref name="window"/> is <see langword="null"/>.
        /// </exception>
        public RibbonCommand(MainWindow window)
        {
            if (window == null)
                throw new ArgumentNullException("MainWindow");

            mainWindow = window;
            keyBinding = new KeyBinding();
            keyBinding.Command = this;
            mainWindow.InputBindings.Add(keyBinding);
        }

        #endregion

        #region ICommand Members

        /// <inheritdoc/>
        public abstract bool CanExecute(object parameter);

        /// <inheritdoc/>
        public event EventHandler CanExecuteChanged;

        /// <inheritdoc/>
        public abstract void Execute(object parameter);

        #endregion

        #region INotifyPropertyChanged Members

        /// <inheritdoc/>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region Protected Methods

        /// <summary>
        /// Raises the <see cref="CanExecuteChanged"/> event on this command instance.
        /// </summary>
        protected void RaiseCanExecuteChanged()
        {
            if (CanExecuteChanged != null)
                CanExecuteChanged(this, EventArgs.Empty);
        }

        /// <summary>
        /// Raises the <see cref="PropertyChanged"/> event on this command instance.
        /// </summary>
        /// <param name="propertyName">
        /// <para>
        /// Type: <see cref="string"/>
        /// </para>
        /// <para>
        /// Name of the property whose value has changed.
        /// </para>
        /// </param>
        protected void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets a reference to the main application window.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="MainWindow"/>
        /// </para>
        /// <para>
        /// The main application window.
        /// </para>
        /// </value>
        public MainWindow ApplicationWindow
        {
            get { return mainWindow; }
        }

        /// <summary>
        /// Gets the reason why this command is currently disabled (cannot be executed).
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="string"/>
        /// </para>
        /// <para>
        /// The textual description of the reason why the command cannot be currently executed.<br/>
        /// </para>
        /// </value>
        public string DisableReason
        {
            get { return disableReason; }
            protected set 
            {
                disableReason = value;
                RaisePropertyChanged("DisableReason");
            }
        }

        /// <summary>
        /// Gets or sets the key gesture associated with this command.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="KeyGesture"/>
        /// </para>
        /// <para>
        /// The key gesture associated with this command.
        /// </para>
        /// </value>
        public KeyGesture Gesture
        {
            get { return keyGesture; }
            set
            {
                keyGesture = value;
                keyBinding.Gesture = keyGesture;

                RaisePropertyChanged("Gesture");
                RaisePropertyChanged("ScreenTipTitle");
            }
        }

        /// <summary>
        /// Gets the text of the screen tip associated with this command.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="string"/>
        /// </para>
        /// <para>
        /// The text of the screen tip associated with this command.
        /// </para>
        /// </value>
        public string ScreenTipText
        {
            get { return screenTipText; }
            protected set
            {
                screenTipText = value;

                RaisePropertyChanged("ScreenTipText");
            }
        }

        /// <summary>
        /// Gets the title of the screen tip associated with this command.
        /// </summary>
        /// <value>
        /// <para>
        /// Type: <see cref="string"/>
        /// </para>
        /// <para>
        /// The title of the screen tip associated with this command.
        /// If a <see cref="KeyGesture"/> is associated with this command,
        /// it is automatically added to the screen tip.
        /// </para>
        /// </value>
        public string ScreenTipTitle
        {
            get 
            { 
                if (keyGesture != null)
                    return String.Format("{0} ({1})", screenTipTitle, keyGesture.GetDisplayStringForCulture(CultureInfo.CurrentCulture));

                return screenTipTitle;
            }
            protected set
            {
                screenTipTitle = value;

                RaisePropertyChanged("ScreenTipTitle");
            }
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds the value of the <see cref="DisableReason"/> property.
        /// </summary>
        private string disableReason;
        /// <summary>
        /// Holds the key binding.
        /// </summary>
        private KeyBinding keyBinding;
        /// <summary>
        /// Holds the key gesture associated with this command.
        /// </summary>
        private KeyGesture keyGesture;
        /// <summary>
        /// Holds a reference to the main application window.
        /// </summary>
        private MainWindow mainWindow;
        /// <summary>
        /// Holds the value of the <see cref="ScreenTipText"/> property.
        /// </summary>
        private string screenTipText;
        /// <summary>
        /// Holds the value of the <see cref="ScreenTipTitle"/> property.
        /// </summary>
        private string screenTipTitle;

        #endregion
    }
}
